/**
 * 
 */
package com.module.bp.engine;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.dalonedrau.jogl.engine.GameApplet;
import com.dalonedrau.jogl.engine.GameController;
import com.dalonedrau.jogl.engine.GameState;
import com.dalonedrau.jogl.opengl.sprite.SpriteImageObjectFactory;
import com.dalonedrau.jogl.opengl.sprite.SpriteTileMap;
import com.dalonedrau.map.Cell;
import com.dalonedrau.map.TileMap;
import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;
import com.dalonedrau.xmlparser.XMLParserUtility;
import com.module.bp.bus.BPHexMap;
import com.module.bp.bus.graph.GraphLoader;

/**
 * Utility class to initialize game data.
 * @author Donald
 */
public final class Init {
	/** the one and only instance of the <code>GameController</code> class. */
	private static Init	instance;
	/**
	 * Gives access to the singleton instance of {@link GameController}.
	 * @return {@link GameController}
	 */
	public static Init getInstance() {
		if (Init.instance == null) {
			Init.instance = new Init();
		}
		return Init.instance;
	}
	/** 
	 * Initializes all game data.
	 * @throws Exception if an error occurs
	 */
	public void initGameData() throws Exception {
	}

	/**
	 * Loads a hex map based on the specified document.
	 * @param fileName the document the map is based on
	 * @throws Exception if an error occurs
	 */
	public void loadHexMap(final String fileName) throws Exception {
		InputStream is = null;
		if (fileName != null
				&& fileName.startsWith("com")) { // jar implementation
			is = getClass().getClassLoader().getResourceAsStream(
							fileName);
		} else { // file implementation
			File file = new File(".\\", fileName);
			// all work is done if the data file exists.
			// otherwise, an error dialog is displayed
			if (file.exists()) {
				is = new FileInputStream(file);
			} else {
				// logger.debug("TextureLoader loadImagesFile()- "
				// + fileName + " did not exist.");
				PooledStringBuilder sb =
						StringBuilderPool.getInstance().getStringBuilder();
				sb.append("Init loadBPMap() - file ");
				sb.append(fileName.toString());
				sb.append(" does not exist in library folder.");
				Exception ex = new Exception(sb.toString());
				sb.returnToPool();
				throw ex;
			}
			file = null;
		}
		Document serviceDoc = XMLParserUtility.getInstance().parseXmlFile(is);
		parseHexMap(serviceDoc);
		BPController.getInstance().setOverworldGraph(
				GraphLoader.getInstance().loadOverworldGraph());
	}
	/**
	 * Loads a tile map based on the specified document.
	 * @param fileName the document the map is based on
	 * @return {@link TileMap}
	 * @throws Exception if an error occurs
	 */
	public TileMap loadTileMap(final String fileName) throws Exception {
		InputStream is = null;
		if (fileName != null
				&& fileName.startsWith("com")) { // jar implementation
			is = getClass().getClassLoader().getResourceAsStream(
							fileName);
		} else { // file implementation
			File file = new File(".\\", fileName);
			// all work is done if the data file exists.
			// otherwise, an error dialog is displayed
			if (file.exists()) {
				is = new FileInputStream(file);
			} else {
				// logger.debug("TextureLoader loadImagesFile()- "
				// + fileName + " did not exist.");
				PooledStringBuilder sb =
						StringBuilderPool.getInstance().getStringBuilder();
				sb.append("Init loadBPMap() - file ");
				sb.append(fileName.toString());
				sb.append(" does not exist in library folder.");
				Exception ex = new Exception(sb.toString());
				sb.returnToPool();
				throw ex;
			}
			file = null;
		}
		Document serviceDoc = XMLParserUtility.getInstance().parseXmlFile(is);
		return parseTileMap(serviceDoc);
	}
	/**
	 * Parses the map's xml document.
	 * @param dom the xml document
	 * @return {@link TileMap}
	 * @throws Exception if an error occurs
	 */
	private TileMap parseTileMap(final Document dom) throws Exception {
		TileMap map = new TileMap();
		Element docEle = dom.getDocumentElement();
		NodeList nl = docEle.getElementsByTagName("layer");
		if (nl != null && nl.getLength() > 0) {
			for (int i = 0; i < nl.getLength(); i++) {
				if (i > 0) {
					map.addLayer();
					map.changeLayer(1);
				}
				// create the cells
				Element element = (Element) nl.item(i);
				createCellsForLayer(element, map);
			}
		}
		return map;
	}
	/**
	 * Parses the map's xml document.
	 * @param dom the xml document
	 * @throws Exception if an error occurs
	 */
	private void parseHexMap(final Document dom) throws Exception {
		Element docEle = dom.getDocumentElement();
		NodeList nl = docEle.getElementsByTagName("mapHex");
		if (nl != null && nl.getLength() > 0) {
			for (int i = 0; i < nl.getLength(); i++) {
				Element element = (Element) nl.item(i);
				int x = 
					XMLParserUtility.getInstance().getIntValue(element, "x");
				int y = 
					XMLParserUtility.getInstance().getIntValue(element, "y");
				int type = 
					XMLParserUtility.getInstance().getIntValue(element, "type");
				String name = 
					XMLParserUtility.getInstance().getTextFromElement(element, 
							"name");
				BPHexMap.getInstance().setHex(x, y, type, name);
			}
		}
	}
	/**
	 * Creates {@link Cell}s to be added to a map created while loading a file.
	 * @param element the xml element being read
	 * @throws Exception if an error occurs
	 */
	private void createCellsForLayer(final Element docEle,
			final TileMap map) throws Exception {
		// get a nodelist of mapHex elements
		NodeList nl = docEle.getElementsByTagName("cell");
		if (nl != null && nl.getLength() > 0) {
			for (int i = 0; i < nl.getLength(); i++) {
				// create the cell
				Element element = (Element) nl.item(i);
				Cell c = createCell(element);
				if (c != null) {
					map.addCell(c);
				}
			}
		}
	}
	/**
	 * Creates a cell to be added to a map created while loading a file.
	 * @param element the xml element being read
	 * @return {@link Cell}
	 * @throws Exception if an error occurs
	 */
	private Cell createCell(final Element element) throws Exception {
		int x = XMLParserUtility.getInstance().getIntValue(element, "x");
		int y = XMLParserUtility.getInstance().getIntValue(element, "y");
		Cell cell = new Cell(x, y);
		try {
			String type = 
				XMLParserUtility.getInstance().getTextFromElement(
						element, "type");
			if (type != null && !type.equalsIgnoreCase("null")) {
				int index = XMLParserUtility.getInstance().getIntValue(element, "index");
				PooledStringBuilder sb = StringBuilderPool.getInstance().getStringBuilder();
				sb.append(type);
				sb.append(index);
				String s = sb.toString();
				sb.returnToPool();
				if (s.equalsIgnoreCase("tile_swamp_water7")
						|| s.equalsIgnoreCase("tile_swamp_water12")
						|| s.equalsIgnoreCase("tile_swamp_grass7")
						|| s.equalsIgnoreCase("tile_swamp_grass12")) {
					s = "tile_swamp0";
				} else if (s.equalsIgnoreCase("tile_grass_road12")) {
					s = "tile_grass_water12";
				} else if (s.equalsIgnoreCase("tile_forest_grass24")
						|| s.equalsIgnoreCase("tile_forest_grass26")) {
					s = "tile_forest_grass12";
				} else if (s.equalsIgnoreCase("tile_mountain_grass24")
						|| s.equalsIgnoreCase("tile_mountain_grass26")) {
					s = "tile_mountain_grass12";
				}
				
				cell.setType(null);
				cell.setImageRefId(
						SpriteImageObjectFactory.getInstance().getImageRefId(s)
						);
				s = null;
			} else {
				cell = null;
			}
		} catch (Exception ex) {
			throw ex;
		}
		return cell;
	}
	/** Loads the game fonts. */
	private static void loadFonts() {
		String mapURL = "com/cob/dat/fonts.xml";
		InputStream is =
				Init.class.getClassLoader().getResourceAsStream(mapURL);
		Document serviceDoc = XMLParserUtility.getInstance().parseXmlFile(is);
		Init.parseFonts(serviceDoc);
	}
	/**
	 * Parses an xml document.
	 * @param dom the xml document
	 */
	private static void parseFonts(final Document dom) {
		try {
			Element docEle = dom.getDocumentElement();
			// get a nodelist of mapHex elements
			NodeList nl = docEle.getElementsByTagName("font");
			if (nl != null && nl.getLength() > 0) {
				for (int i = 0; i < nl.getLength(); i++) {
					Element element = (Element) nl.item(i);
					String name =
							XMLParserUtility.getInstance().getTextFromElement(
									element, "name");
					int point =
							XMLParserUtility.getInstance().getIntValue(
									element, "point");
					// GameFont font = new GameFont(name, point);
				}
			}
		} catch (Exception ex) {
			JOGLErrorHandler.getInstance().fatalError(ex);
		}
	}
	/** Hidden constructor. */
	private Init() {}
}
